Skip to content

feat(bounty): builder "my bounties" activity + rewards receipt - #651

Merged
Benjtalkshow merged 1 commit into
boundlessfi:feat/t-replacefrom
Benjtalkshow:feat/bounty-my-bounties
Jun 25, 2026
Merged

feat(bounty): builder "my bounties" activity + rewards receipt#651
Benjtalkshow merged 1 commit into
boundlessfi:feat/t-replacefrom
Benjtalkshow:feat/bounty-my-bounties

Conversation

@Benjtalkshow

Copy link
Copy Markdown
Collaborator

Closes #626.

Stacked on #643 (#621 data layer). Until #643 merges into feat/t-replace, this PR's diff also shows the #621 commit; it reduces to just the my-bounties surfaces once #643 lands.

What

The builder's /me surfaces for bounty applications, submissions, and reward receipts — consuming the participant dashboard (boundless-nestjs #332) + earnings (#335).

  • Data layer — added the useMyBountyActivity reads deferred in FE: features/bounties participant data layer (escrow client + hooks) #621: useMyBountyApplications / useMyBountySubmissions calling merge to prod #332's /bounties/me/*. Those aren't in the generated schema yet, so they go through the legacy axios api (cookie auth) with hand-typed rows and retry: false, degrading to empty until Feat/hackthon features #343 merges.
  • /me/bounties pageApplications / Submissions tabs. Applications show mode + status badge (Submitted / Shortlisted / Selected / Not selected / Withdrawn / Claimed); submissions show progress (Submitted → In review → Won / Closed), and for won rows the reward amount + a payout tx-hash link. Rows link to the detail page; loading/empty states.
  • Sidebar — a "My Bounties" nav entry (IconTarget).
  • /me/earnings — the page already renders breakdown.bounties + activities generically (so Collins #335 surfaces them automatically); added a "View tx" link to reward activities (the on-chain receipt), casting txHash until codegen.

Scope boundaries

Testing

  • Pre-commit type-check / eslint / prettier / build all pass.
  • The earnings page works against the live /users/earnings; the my-bounties data can't be smoke-tested headless (endpoint not live yet).

@vercel

vercel Bot commented Jun 24, 2026

Copy link
Copy Markdown

@Benjtalkshow is attempting to deploy a commit to the Threadflow Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b61a13d4-b679-4b30-8dc1-2f3df1748c59

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

The builder's /me surfaces for bounty applications, submissions, and reward
receipts, consuming the participant dashboard (boundlessfi#332) + earnings (boundlessfi#335).

- data layer: useMyBountyApplications / useMyBountySubmissions (the deferred
  useMyBountyActivity) via the legacy axios api (hand-typed rows, retry:false,
  degrading to empty until boundlessfi#332 lands in the schema)
- /me/bounties page: Applications + Submissions tabs with status/progress
  badges; won submissions show the reward amount + a payout tx-hash link;
  rows link to the detail page
- sidebar: "My Bounties" nav entry
- /me/earnings: the page already renders breakdown.bounties + activities
  generically (so boundlessfi#335 surfaces them); add a "View tx" link to reward
  activities (txHash cast until codegen)

Closes boundlessfi#626
@Benjtalkshow
Benjtalkshow force-pushed the feat/bounty-my-bounties branch from 1b2bea7 to 8aa4be6 Compare June 25, 2026 01:06
@Benjtalkshow
Benjtalkshow merged commit d03d1a5 into boundlessfi:feat/t-replace Jun 25, 2026
1 of 2 checks passed
0xdevcollins added a commit that referenced this pull request Jun 27, 2026
…pport (#663)

* feat: integrate treasury management features and refactor hackathon orchestration and API client architecture.

* chore: update package-lock.json dependencies

* chore: update pre-push husky hook to perform full type-checks and production builds

* refactor: remove DevelopmentStatusModal from global layout

* feat: task-first Winners page, judging UX, private access, treasury receipts/send

Winners: new task-first Winners section (pick winner per prize with engine default, inline stacking confirm, deliberate 'Don't award' + unawarded-funds acknowledgement); /rewards redirects to /winners; staged Pick -> Confirm -> Pay.

Judging: slimmed Results tab to read-only standings + 'Go to Winners'; criterionId name fix; AI scorecards, recommendation thresholds, CSV judge import, tracks + custom questions wizard sections; validation + empty-state polish.

Public: private + password access gate, community links, card private badge. Treasury: receipts + Send funds. Removed the stacking toggle from prize setup.


* feat(bounty): ModeTab + SubmissionModelTab for the Configure wizard (#599) (#611)

The net-new bounty UI with no hackathon analog: the two-axis mode picker and
the mode-conditional submission settings that drive all six combinations.

- modeSchema.ts: plain taxonomy unions (entryType x claimType), the
  computeBountyModeLabel helper, and getModeFields — the mode -> field matrix
  derived functionally from the publish gate (validateTwoAxisMode) so it cannot
  drift from the backend.
- submissionModelSchema.ts: makeSubmissionModelSchema(mode), a mode-aware Zod
  factory whose required fields and the >=2 floors (maxApplicants for open
  competition, shortlistSize for application competition) mirror the server gate.
- ModeTab.tsx: entry x claim picker, a winners stepper (1-3) for competitions,
  and a live computed mode label.
- SubmissionModelTab.tsx: renders each field per the matrix (required / optional
  / hidden) and shows submissionVisibility read-only, forced by the mode
  (HIDDEN_UNTIL_DEADLINE for competitions).

Standalone components (props: mode, onSave, onContinue, initialData, isLoading);
they wire into the wizard shell + routes in #597 / #598.

* feat(bounty): features/bounties data layer (types, keys, draft + escrow) (#596) (#612)

Adds the features/bounties/ data layer for the v1 app, mirroring
features/hackathons/. REST-only via the typed openapi-fetch client; every
server shape is aliased from the backend-generated schema so it cannot drift.

- types.ts: aliases the generated draft + escrow DTOs (BountyDraft,
  UpdateBountyDraftBody, the four section types, BountyEscrowOpResponse,
  PublishBountyEscrowRequest, ...). Derives the two-axis taxonomy from the
  generated mode DTO, superseding the local stubs in the ModeTab.
- api/keys.ts: bountyKeys factory.
- api/draft-client.ts + use-draft.ts: imperative CRUD plus the
  useDraft / useDraftList / useCreateDraft / useUpdateDraft / useDeleteDraft
  hooks against /organizations/{organizationId}/bounties/draft[/{id}] + /drafts.
- api/escrow-client.ts + use-escrow.ts: organizer escrow calls (publish /
  cancel / select-winners / submit-signed / poll) plus useEscrowOp +
  useEscrowOpRunner, mirroring the hackathon machinery (MANAGED polls; EXTERNAL
  signs -> submit -> poll) bounty-scoped.
- index.ts: public surface.

Regenerates lib/api/generated/schema.d.ts from the v2 backend so the bounty
draft paths/DTOs are present.

* feat(bounty): wizard shell + step/draft machinery (#598) (#613)

* feat(bounty): features/bounties data layer (types, keys, draft + escrow) (#596)

Adds the features/bounties/ data layer for the v1 app, mirroring
features/hackathons/. REST-only via the typed openapi-fetch client; every
server shape is aliased from the backend-generated schema so it cannot drift.

- types.ts: aliases the generated draft + escrow DTOs (BountyDraft,
  UpdateBountyDraftBody, the four section types, BountyEscrowOpResponse,
  PublishBountyEscrowRequest, ...). Derives the two-axis taxonomy from the
  generated mode DTO, superseding the local stubs in the ModeTab.
- api/keys.ts: bountyKeys factory.
- api/draft-client.ts + use-draft.ts: imperative CRUD plus the
  useDraft / useDraftList / useCreateDraft / useUpdateDraft / useDeleteDraft
  hooks against /organizations/{organizationId}/bounties/draft[/{id}] + /drafts.
- api/escrow-client.ts + use-escrow.ts: organizer escrow calls (publish /
  cancel / select-winners / submit-signed / poll) plus useEscrowOp +
  useEscrowOpRunner, mirroring the hackathon machinery (MANAGED polls; EXTERNAL
  signs -> submit -> poll) bounty-scoped.
- index.ts: public surface.

Regenerates lib/api/generated/schema.d.ts from the v2 backend so the bounty
draft paths/DTOs are present.

* feat(bounty): wizard shell + step/draft machinery (#598)

Adds the bounty Configure wizard orchestrator and its step + draft state,
mirroring the hackathon wizard. No AI assist.

- components/organization/bounties/new/constants.ts: StepKey
  (scope/mode/submission/reward/review), STEP_ORDER, BountyFormData, and
  isBountyStepDataValid.
- hooks/use-bounty-steps.ts: URL ?step= navigation (free-roam) with a
  presentational step-status map.
- hooks/use-bounty-draft.ts: lazy create (ensureDraftId) then per-section PATCH,
  resume via useDraft, and transformBountyFromApi (sections -> form state;
  winnerCount derived from prize tiers, ISO dates trimmed for the inputs).
- components/organization/bounties/new/NewBountyTab.tsx: orchestrator wiring
  steps + draft + per-step save, persisting ?draftId= for resume, and threading
  the chosen mode from ModeTab into SubmissionModelTab.

Scope/Reward/Review tabs (#600) and the publish + funding flow (#601) are left
as marked placeholders with their save/navigate/draftId seams in place; this
satisfies the acceptance criteria (navigate, autosave, resume) without
speculative publish UI that depends on the unbuilt publish hook.

* feat(bounty): Scope + Reward + Review tabs and Zod schemas (#600) (#614)

Completes the editable surface of the bounty Configure wizard, dropping the
three remaining tabs into the seams the shell (#598) left.

- tabs/schemas/scopeSchema.ts: title, description, optional GitHub issue
  url/number, optional project/window.
- tabs/schemas/rewardSchema.ts: makeRewardSchema(claimType) — exactly one tier
  for single claim, 1-3 for a competition; amounts > 0, unique positions
  including position 1 (mirrors the publish gate's deriveWinnerDistribution).
- lib/utils/bounty-escrow.ts: adapts the bounty reward shape to reuse the
  hackathon prize-pool math (getTotalPrizePoolForFunding, buildWinnerDistribution,
  2.5% PLATFORM_FEE) rather than duplicating it.
- tabs/ScopeTab.tsx: scope form.
- tabs/RewardTab.tsx: currency + mode-driven prize tiers (field array sized to
  the winner count) with a live prize-pool / fee / total preview.
- tabs/ReviewTab.tsx: per-section summary, validation summary, funding totals,
  and a publish CTA disabled until every section validates.
- NewBountyTab.tsx + constants.ts: wire the three tabs into the wizard; the form
  snapshot now uses the per-tab form schema types.

Reward currency is collected in the Reward step (the backend section that
persists it) rather than Scope, so it round-trips. The publish action is a
placeholder pending the escrow publish flow (#601); the disabled-until-valid
gate is wired here.

* feat(bounty): use-bounty-publish (escrow publish via shared runner) (#601) (#615)

* feat(bounty): Scope + Reward + Review tabs and Zod schemas (#600)

Completes the editable surface of the bounty Configure wizard, dropping the
three remaining tabs into the seams the shell (#598) left.

- tabs/schemas/scopeSchema.ts: title, description, optional GitHub issue
  url/number, optional project/window.
- tabs/schemas/rewardSchema.ts: makeRewardSchema(claimType) — exactly one tier
  for single claim, 1-3 for a competition; amounts > 0, unique positions
  including position 1 (mirrors the publish gate's deriveWinnerDistribution).
- lib/utils/bounty-escrow.ts: adapts the bounty reward shape to reuse the
  hackathon prize-pool math (getTotalPrizePoolForFunding, buildWinnerDistribution,
  2.5% PLATFORM_FEE) rather than duplicating it.
- tabs/ScopeTab.tsx: scope form.
- tabs/RewardTab.tsx: currency + mode-driven prize tiers (field array sized to
  the winner count) with a live prize-pool / fee / total preview.
- tabs/ReviewTab.tsx: per-section summary, validation summary, funding totals,
  and a publish CTA disabled until every section validates.
- NewBountyTab.tsx + constants.ts: wire the three tabs into the wizard; the form
  snapshot now uses the per-tab form schema types.

Reward currency is collected in the Reward step (the backend section that
persists it) rather than Scope, so it round-trips. The publish action is a
placeholder pending the escrow publish flow (#601); the disabled-until-valid
gate is wired here.

* feat(bounty): use-bounty-publish (escrow publish via shared runner) (#601)

Wires the bounty publish action, mirroring use-hackathon-publish.

- hooks/use-bounty-publish.ts: builds PublishBountyEscrowDto (ownerAddress,
  tokenAddress via getTokenAddress('USDC'), budget = sum of tier amounts,
  submissionDeadline as unix from the draft deadline, applicationCreditCost,
  winnerDistribution via the shared buildBountyWinnerDistribution, fundingMode)
  and drives it with useEscrowOpRunner: MANAGED returns PENDING_CONFIRM then
  polls; EXTERNAL signs the returned XDR via signXdrWithKit then submits + polls.
  On COMPLETED the bounty has moved draft_awaiting_funding -> open. Pre-flight
  resumes an in-flight op, short-circuits an already-published bounty, and runs a
  MANAGED USDC balance check (pool + 2.5% fee).
- NewBountyTab.tsx: replace the Review placeholder with the real publish() and
  wire isPublishing into the CTA.

Treasury funding (sourceWalletId) is omitted until the backend treasury-parity
issue (boundless-nestjs #314) lands; MANAGED + EXTERNAL are supported. The
funding-source picker + progress modal remain a follow-up; the hook exposes the
escrow phase/error/txHash they need.

* feat(bounty): routes + organization bounty list page (#597) (#616)

Adds the organizer bounty routes, mirroring the hackathon route tree, and the
published-list data needed by the list page.

- app/(landing)/organizations/[id]/bounties/page.tsx: list page with a Drafts
  section (resume links + status badges + mode label / section count) and a
  Published section (status badges + reward), plus a "Host a bounty" CTA.
- .../bounties/new/page.tsx: renders <NewBountyTab organizationId={id} />.
- .../bounties/drafts/[draftId]/page.tsx: renders
  <NewBountyTab organizationId={id} draftId={draftId} />.
- features/bounties/api/core.ts + use-bounties.ts: listOrganizationBounties +
  useOrganizationBounties for the root list (the backend root GET has no
  response DTO, so the row shape is projected to OrganizationBountyListItem).

The pages mount the existing wizard shell (#598); the list separates drafts
(draft / draft_awaiting_funding) from published bounties so they don't
double-list.

* feat(bounty): sidebar nav entry + Post Bounty quick action (#602) (#617)

Adds a Bounties menu item (/organizations/{orgId}/bounties) and a Post Bounty
quick action (/organizations/{orgId}/bounties/new) to OrganizationSidebar, so
organizers can reach the bounty list + Configure wizard.

Codegen reconcile: re-ran npm run codegen against the v2 backend; the committed
lib/api/generated/schema.d.ts already matches (BountyDraftResponseDto +
UpdateBountyDraftDto present, no drift), so no schema change is needed.

* feat(bounty): wizard enhancements + hackathon-style org bounty list (#618)

* feat(bounty): wizard enhancements (resources step, currency, reputation, nav)

- Resources: new optional Resources step (links + PDF/DOC/PPT/MD uploads),
  mirroring the hackathon resources tab; never blocks publish. Reuses a now
  configurable ResourceFileUpload (folder/tags/accepted types props; unique
  input id per row).
- Reward currency: dropdown of USDC (default) / XLM (disabled) with real token
  logos, replacing the free-text field.
- Reputation: per-category minimum floor (development highest); the organizer
  can raise it but not drop below the category baseline.
- Navigation: Back button on every step after the first.
- Scope: category chips + searchable country dropdown with flags + markdown
  description; GitHub issue URL required only for development.
- Publish: redirect to the organizer's bounty list once publish finalizes.
- Dev-only "Fill with mock" button to populate every section at once.

* feat(bounty): hackathon-style org bounty list + delete-draft confirm

- Rebuild the organization bounty list page in the hackathon style: sticky
  header with stats, Published/Drafts tabs, search + sort, and a banner-less
  reward-focused card grid (draft cards show a progress bar + resume link).
- Deleting a draft now opens a confirmation modal (DeleteBountyDraftDialog)
  instead of deleting on the first click.
- Expose `_count.submissions` on the org bounty list item for the cards.

* Feat/crowdfunding (#620)

* feat(bounty): features/bounties data layer (types, keys, draft + escrow) (#596)

Adds the features/bounties/ data layer for the v1 app, mirroring
features/hackathons/. REST-only via the typed openapi-fetch client; every
server shape is aliased from the backend-generated schema so it cannot drift.

- types.ts: aliases the generated draft + escrow DTOs (BountyDraft,
  UpdateBountyDraftBody, the four section types, BountyEscrowOpResponse,
  PublishBountyEscrowRequest, ...). Derives the two-axis taxonomy from the
  generated mode DTO, superseding the local stubs in the ModeTab.
- api/keys.ts: bountyKeys factory.
- api/draft-client.ts + use-draft.ts: imperative CRUD plus the
  useDraft / useDraftList / useCreateDraft / useUpdateDraft / useDeleteDraft
  hooks against /organizations/{organizationId}/bounties/draft[/{id}] + /drafts.
- api/escrow-client.ts + use-escrow.ts: organizer escrow calls (publish /
  cancel / select-winners / submit-signed / poll) plus useEscrowOp +
  useEscrowOpRunner, mirroring the hackathon machinery (MANAGED polls; EXTERNAL
  signs -> submit -> poll) bounty-scoped.
- index.ts: public surface.

Regenerates lib/api/generated/schema.d.ts from the v2 backend so the bounty
draft paths/DTOs are present.

* feat(bounty): wizard shell + step/draft machinery (#598)

Adds the bounty Configure wizard orchestrator and its step + draft state,
mirroring the hackathon wizard. No AI assist.

- components/organization/bounties/new/constants.ts: StepKey
  (scope/mode/submission/reward/review), STEP_ORDER, BountyFormData, and
  isBountyStepDataValid.
- hooks/use-bounty-steps.ts: URL ?step= navigation (free-roam) with a
  presentational step-status map.
- hooks/use-bounty-draft.ts: lazy create (ensureDraftId) then per-section PATCH,
  resume via useDraft, and transformBountyFromApi (sections -> form state;
  winnerCount derived from prize tiers, ISO dates trimmed for the inputs).
- components/organization/bounties/new/NewBountyTab.tsx: orchestrator wiring
  steps + draft + per-step save, persisting ?draftId= for resume, and threading
  the chosen mode from ModeTab into SubmissionModelTab.

Scope/Reward/Review tabs (#600) and the publish + funding flow (#601) are left
as marked placeholders with their save/navigate/draftId seams in place; this
satisfies the acceptance criteria (navigate, autosave, resume) without
speculative publish UI that depends on the unbuilt publish hook.

* feat: implement multi-step crowdfunding campaign wizard with milestone management

* feat(crowdfunding): v2 public pages, builder dashboard, milestone tracking

- Redesigned public listing (ProjectCard) and detail page with proper
  lifecycle states, voting panel, contributor list, and fully-funded detection
- Added public milestone list + detail pages under /crowdfunding/[slug]/milestones
- Builder per-campaign management: tabbed layout (overview / milestones /
  contributions) with shared header showing milestone X/Y progress and
  Fully Funded badge once fundingRaised >= fundingGoal
- Milestone status sourced from milestoneState() utility: claimedAt-based
  "paid out" detection replaces stale reviewStatus === 'completed' checks
- CampaignStatusBanner: shows milestone delivery bar and Fully Funded label
  during the FUNDING phase when goal is reached
- milestones-metrics: completedAmount correctly sums paid-out milestones;
  inProgress checks SUBMITTED/UNDER_REVIEW enum values
- ProjectCard: switches from funding bar to milestone X/Y bar on fully funded;
  footer and status badge update to Fully Funded (green)
- lib/crowdfunding/status.ts: single source of truth for all campaign and
  milestone status copy and tone

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: update lockfile dependencies for package-lock.json

---------

Co-authored-by: Benjtalkshow <chinedubenj@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* Feat/crowdfunding (#642)

* feat(bounty): features/bounties data layer (types, keys, draft + escrow) (#596)

Adds the features/bounties/ data layer for the v1 app, mirroring
features/hackathons/. REST-only via the typed openapi-fetch client; every
server shape is aliased from the backend-generated schema so it cannot drift.

- types.ts: aliases the generated draft + escrow DTOs (BountyDraft,
  UpdateBountyDraftBody, the four section types, BountyEscrowOpResponse,
  PublishBountyEscrowRequest, ...). Derives the two-axis taxonomy from the
  generated mode DTO, superseding the local stubs in the ModeTab.
- api/keys.ts: bountyKeys factory.
- api/draft-client.ts + use-draft.ts: imperative CRUD plus the
  useDraft / useDraftList / useCreateDraft / useUpdateDraft / useDeleteDraft
  hooks against /organizations/{organizationId}/bounties/draft[/{id}] + /drafts.
- api/escrow-client.ts + use-escrow.ts: organizer escrow calls (publish /
  cancel / select-winners / submit-signed / poll) plus useEscrowOp +
  useEscrowOpRunner, mirroring the hackathon machinery (MANAGED polls; EXTERNAL
  signs -> submit -> poll) bounty-scoped.
- index.ts: public surface.

Regenerates lib/api/generated/schema.d.ts from the v2 backend so the bounty
draft paths/DTOs are present.

* feat(bounty): wizard shell + step/draft machinery (#598)

Adds the bounty Configure wizard orchestrator and its step + draft state,
mirroring the hackathon wizard. No AI assist.

- components/organization/bounties/new/constants.ts: StepKey
  (scope/mode/submission/reward/review), STEP_ORDER, BountyFormData, and
  isBountyStepDataValid.
- hooks/use-bounty-steps.ts: URL ?step= navigation (free-roam) with a
  presentational step-status map.
- hooks/use-bounty-draft.ts: lazy create (ensureDraftId) then per-section PATCH,
  resume via useDraft, and transformBountyFromApi (sections -> form state;
  winnerCount derived from prize tiers, ISO dates trimmed for the inputs).
- components/organization/bounties/new/NewBountyTab.tsx: orchestrator wiring
  steps + draft + per-step save, persisting ?draftId= for resume, and threading
  the chosen mode from ModeTab into SubmissionModelTab.

Scope/Reward/Review tabs (#600) and the publish + funding flow (#601) are left
as marked placeholders with their save/navigate/draftId seams in place; this
satisfies the acceptance criteria (navigate, autosave, resume) without
speculative publish UI that depends on the unbuilt publish hook.

* feat: implement multi-step crowdfunding campaign wizard with milestone management

* feat(crowdfunding): v2 public pages, builder dashboard, milestone tracking

- Redesigned public listing (ProjectCard) and detail page with proper
  lifecycle states, voting panel, contributor list, and fully-funded detection
- Added public milestone list + detail pages under /crowdfunding/[slug]/milestones
- Builder per-campaign management: tabbed layout (overview / milestones /
  contributions) with shared header showing milestone X/Y progress and
  Fully Funded badge once fundingRaised >= fundingGoal
- Milestone status sourced from milestoneState() utility: claimedAt-based
  "paid out" detection replaces stale reviewStatus === 'completed' checks
- CampaignStatusBanner: shows milestone delivery bar and Fully Funded label
  during the FUNDING phase when goal is reached
- milestones-metrics: completedAmount correctly sums paid-out milestones;
  inProgress checks SUBMITTED/UNDER_REVIEW enum values
- ProjectCard: switches from funding bar to milestone X/Y bar on fully funded;
  footer and status badge update to Fully Funded (green)
- lib/crowdfunding/status.ts: single source of truth for all campaign and
  milestone status copy and tone

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: update lockfile dependencies for package-lock.json

* refactor: standardize API error extraction to support array-based messages across crowdfunding components

* refactor: restructure StoryStep inputs, enable sidebar navigation, and update campaign wizard validation logic

---------

Co-authored-by: Benjtalkshow <chinedubenj@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* Feat/crowdfunding (#644)

* feat(bounty): features/bounties data layer (types, keys, draft + escrow) (#596)

Adds the features/bounties/ data layer for the v1 app, mirroring
features/hackathons/. REST-only via the typed openapi-fetch client; every
server shape is aliased from the backend-generated schema so it cannot drift.

- types.ts: aliases the generated draft + escrow DTOs (BountyDraft,
  UpdateBountyDraftBody, the four section types, BountyEscrowOpResponse,
  PublishBountyEscrowRequest, ...). Derives the two-axis taxonomy from the
  generated mode DTO, superseding the local stubs in the ModeTab.
- api/keys.ts: bountyKeys factory.
- api/draft-client.ts + use-draft.ts: imperative CRUD plus the
  useDraft / useDraftList / useCreateDraft / useUpdateDraft / useDeleteDraft
  hooks against /organizations/{organizationId}/bounties/draft[/{id}] + /drafts.
- api/escrow-client.ts + use-escrow.ts: organizer escrow calls (publish /
  cancel / select-winners / submit-signed / poll) plus useEscrowOp +
  useEscrowOpRunner, mirroring the hackathon machinery (MANAGED polls; EXTERNAL
  signs -> submit -> poll) bounty-scoped.
- index.ts: public surface.

Regenerates lib/api/generated/schema.d.ts from the v2 backend so the bounty
draft paths/DTOs are present.

* feat(bounty): wizard shell + step/draft machinery (#598)

Adds the bounty Configure wizard orchestrator and its step + draft state,
mirroring the hackathon wizard. No AI assist.

- components/organization/bounties/new/constants.ts: StepKey
  (scope/mode/submission/reward/review), STEP_ORDER, BountyFormData, and
  isBountyStepDataValid.
- hooks/use-bounty-steps.ts: URL ?step= navigation (free-roam) with a
  presentational step-status map.
- hooks/use-bounty-draft.ts: lazy create (ensureDraftId) then per-section PATCH,
  resume via useDraft, and transformBountyFromApi (sections -> form state;
  winnerCount derived from prize tiers, ISO dates trimmed for the inputs).
- components/organization/bounties/new/NewBountyTab.tsx: orchestrator wiring
  steps + draft + per-step save, persisting ?draftId= for resume, and threading
  the chosen mode from ModeTab into SubmissionModelTab.

Scope/Reward/Review tabs (#600) and the publish + funding flow (#601) are left
as marked placeholders with their save/navigate/draftId seams in place; this
satisfies the acceptance criteria (navigate, autosave, resume) without
speculative publish UI that depends on the unbuilt publish hook.

* feat: implement multi-step crowdfunding campaign wizard with milestone management

* feat(crowdfunding): v2 public pages, builder dashboard, milestone tracking

- Redesigned public listing (ProjectCard) and detail page with proper
  lifecycle states, voting panel, contributor list, and fully-funded detection
- Added public milestone list + detail pages under /crowdfunding/[slug]/milestones
- Builder per-campaign management: tabbed layout (overview / milestones /
  contributions) with shared header showing milestone X/Y progress and
  Fully Funded badge once fundingRaised >= fundingGoal
- Milestone status sourced from milestoneState() utility: claimedAt-based
  "paid out" detection replaces stale reviewStatus === 'completed' checks
- CampaignStatusBanner: shows milestone delivery bar and Fully Funded label
  during the FUNDING phase when goal is reached
- milestones-metrics: completedAmount correctly sums paid-out milestones;
  inProgress checks SUBMITTED/UNDER_REVIEW enum values
- ProjectCard: switches from funding bar to milestone X/Y bar on fully funded;
  footer and status badge update to Fully Funded (green)
- lib/crowdfunding/status.ts: single source of truth for all campaign and
  milestone status copy and tone

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: update lockfile dependencies for package-lock.json

* refactor: standardize API error extraction to support array-based messages across crowdfunding components

* refactor: restructure StoryStep inputs, enable sidebar navigation, and update campaign wizard validation logic

* feat: replace textarea with AnnouncementEditor and add markdown rendering for campaign project details

---------

Co-authored-by: Benjtalkshow <chinedubenj@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* Feat/crowdfunding (#648)

* feat(bounty): features/bounties data layer (types, keys, draft + escrow) (#596)

Adds the features/bounties/ data layer for the v1 app, mirroring
features/hackathons/. REST-only via the typed openapi-fetch client; every
server shape is aliased from the backend-generated schema so it cannot drift.

- types.ts: aliases the generated draft + escrow DTOs (BountyDraft,
  UpdateBountyDraftBody, the four section types, BountyEscrowOpResponse,
  PublishBountyEscrowRequest, ...). Derives the two-axis taxonomy from the
  generated mode DTO, superseding the local stubs in the ModeTab.
- api/keys.ts: bountyKeys factory.
- api/draft-client.ts + use-draft.ts: imperative CRUD plus the
  useDraft / useDraftList / useCreateDraft / useUpdateDraft / useDeleteDraft
  hooks against /organizations/{organizationId}/bounties/draft[/{id}] + /drafts.
- api/escrow-client.ts + use-escrow.ts: organizer escrow calls (publish /
  cancel / select-winners / submit-signed / poll) plus useEscrowOp +
  useEscrowOpRunner, mirroring the hackathon machinery (MANAGED polls; EXTERNAL
  signs -> submit -> poll) bounty-scoped.
- index.ts: public surface.

Regenerates lib/api/generated/schema.d.ts from the v2 backend so the bounty
draft paths/DTOs are present.

* feat(bounty): wizard shell + step/draft machinery (#598)

Adds the bounty Configure wizard orchestrator and its step + draft state,
mirroring the hackathon wizard. No AI assist.

- components/organization/bounties/new/constants.ts: StepKey
  (scope/mode/submission/reward/review), STEP_ORDER, BountyFormData, and
  isBountyStepDataValid.
- hooks/use-bounty-steps.ts: URL ?step= navigation (free-roam) with a
  presentational step-status map.
- hooks/use-bounty-draft.ts: lazy create (ensureDraftId) then per-section PATCH,
  resume via useDraft, and transformBountyFromApi (sections -> form state;
  winnerCount derived from prize tiers, ISO dates trimmed for the inputs).
- components/organization/bounties/new/NewBountyTab.tsx: orchestrator wiring
  steps + draft + per-step save, persisting ?draftId= for resume, and threading
  the chosen mode from ModeTab into SubmissionModelTab.

Scope/Reward/Review tabs (#600) and the publish + funding flow (#601) are left
as marked placeholders with their save/navigate/draftId seams in place; this
satisfies the acceptance criteria (navigate, autosave, resume) without
speculative publish UI that depends on the unbuilt publish hook.

* feat: implement multi-step crowdfunding campaign wizard with milestone management

* feat(crowdfunding): v2 public pages, builder dashboard, milestone tracking

- Redesigned public listing (ProjectCard) and detail page with proper
  lifecycle states, voting panel, contributor list, and fully-funded detection
- Added public milestone list + detail pages under /crowdfunding/[slug]/milestones
- Builder per-campaign management: tabbed layout (overview / milestones /
  contributions) with shared header showing milestone X/Y progress and
  Fully Funded badge once fundingRaised >= fundingGoal
- Milestone status sourced from milestoneState() utility: claimedAt-based
  "paid out" detection replaces stale reviewStatus === 'completed' checks
- CampaignStatusBanner: shows milestone delivery bar and Fully Funded label
  during the FUNDING phase when goal is reached
- milestones-metrics: completedAmount correctly sums paid-out milestones;
  inProgress checks SUBMITTED/UNDER_REVIEW enum values
- ProjectCard: switches from funding bar to milestone X/Y bar on fully funded;
  footer and status badge update to Fully Funded (green)
- lib/crowdfunding/status.ts: single source of truth for all campaign and
  milestone status copy and tone

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: update lockfile dependencies for package-lock.json

* refactor: standardize API error extraction to support array-based messages across crowdfunding components

* refactor: restructure StoryStep inputs, enable sidebar navigation, and update campaign wizard validation logic

* feat: replace textarea with AnnouncementEditor and add markdown rendering for campaign project details

* fix: useCampaign routes UUID params to fetchCampaignById

Post-create redirect lands on /me/crowdfunding/{uuid}. The hook was
always calling the slug endpoint which rejected UUIDs. Now detects
UUID format and uses the correct /api/crowdfunding/{id} endpoint.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: auth-gate voting/contribute + branded fallback banner

- VotePanel: unauthenticated users see "Sign in to vote" instead of
  the yes/no buttons
- Public page: "Back this project" replaced with "Sign in to back this
  project" link for unauthenticated visitors
- Fallback banner (no banner set): full-height Boundless-branded SVG
  with dot grid, concentric arcs in brand colour, and faint wordmark
  instead of the flat zinc gradient div

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Benjtalkshow <chinedubenj@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* Feat/crowdfunding (#650)

* feat(bounty): features/bounties data layer (types, keys, draft + escrow) (#596)

Adds the features/bounties/ data layer for the v1 app, mirroring
features/hackathons/. REST-only via the typed openapi-fetch client; every
server shape is aliased from the backend-generated schema so it cannot drift.

- types.ts: aliases the generated draft + escrow DTOs (BountyDraft,
  UpdateBountyDraftBody, the four section types, BountyEscrowOpResponse,
  PublishBountyEscrowRequest, ...). Derives the two-axis taxonomy from the
  generated mode DTO, superseding the local stubs in the ModeTab.
- api/keys.ts: bountyKeys factory.
- api/draft-client.ts + use-draft.ts: imperative CRUD plus the
  useDraft / useDraftList / useCreateDraft / useUpdateDraft / useDeleteDraft
  hooks against /organizations/{organizationId}/bounties/draft[/{id}] + /drafts.
- api/escrow-client.ts + use-escrow.ts: organizer escrow calls (publish /
  cancel / select-winners / submit-signed / poll) plus useEscrowOp +
  useEscrowOpRunner, mirroring the hackathon machinery (MANAGED polls; EXTERNAL
  signs -> submit -> poll) bounty-scoped.
- index.ts: public surface.

Regenerates lib/api/generated/schema.d.ts from the v2 backend so the bounty
draft paths/DTOs are present.

* feat(bounty): wizard shell + step/draft machinery (#598)

Adds the bounty Configure wizard orchestrator and its step + draft state,
mirroring the hackathon wizard. No AI assist.

- components/organization/bounties/new/constants.ts: StepKey
  (scope/mode/submission/reward/review), STEP_ORDER, BountyFormData, and
  isBountyStepDataValid.
- hooks/use-bounty-steps.ts: URL ?step= navigation (free-roam) with a
  presentational step-status map.
- hooks/use-bounty-draft.ts: lazy create (ensureDraftId) then per-section PATCH,
  resume via useDraft, and transformBountyFromApi (sections -> form state;
  winnerCount derived from prize tiers, ISO dates trimmed for the inputs).
- components/organization/bounties/new/NewBountyTab.tsx: orchestrator wiring
  steps + draft + per-step save, persisting ?draftId= for resume, and threading
  the chosen mode from ModeTab into SubmissionModelTab.

Scope/Reward/Review tabs (#600) and the publish + funding flow (#601) are left
as marked placeholders with their save/navigate/draftId seams in place; this
satisfies the acceptance criteria (navigate, autosave, resume) without
speculative publish UI that depends on the unbuilt publish hook.

* feat: implement multi-step crowdfunding campaign wizard with milestone management

* feat(crowdfunding): v2 public pages, builder dashboard, milestone tracking

- Redesigned public listing (ProjectCard) and detail page with proper
  lifecycle states, voting panel, contributor list, and fully-funded detection
- Added public milestone list + detail pages under /crowdfunding/[slug]/milestones
- Builder per-campaign management: tabbed layout (overview / milestones /
  contributions) with shared header showing milestone X/Y progress and
  Fully Funded badge once fundingRaised >= fundingGoal
- Milestone status sourced from milestoneState() utility: claimedAt-based
  "paid out" detection replaces stale reviewStatus === 'completed' checks
- CampaignStatusBanner: shows milestone delivery bar and Fully Funded label
  during the FUNDING phase when goal is reached
- milestones-metrics: completedAmount correctly sums paid-out milestones;
  inProgress checks SUBMITTED/UNDER_REVIEW enum values
- ProjectCard: switches from funding bar to milestone X/Y bar on fully funded;
  footer and status badge update to Fully Funded (green)
- lib/crowdfunding/status.ts: single source of truth for all campaign and
  milestone status copy and tone

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: update lockfile dependencies for package-lock.json

* refactor: standardize API error extraction to support array-based messages across crowdfunding components

* refactor: restructure StoryStep inputs, enable sidebar navigation, and update campaign wizard validation logic

* feat: replace textarea with AnnouncementEditor and add markdown rendering for campaign project details

* fix: useCampaign routes UUID params to fetchCampaignById

Post-create redirect lands on /me/crowdfunding/{uuid}. The hook was
always calling the slug endpoint which rejected UUIDs. Now detects
UUID format and uses the correct /api/crowdfunding/{id} endpoint.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: auth-gate voting/contribute + branded fallback banner

- VotePanel: unauthenticated users see "Sign in to vote" instead of
  the yes/no buttons
- Public page: "Back this project" replaced with "Sign in to back this
  project" link for unauthenticated visitors
- Fallback banner (no banner set): full-height Boundless-branded SVG
  with dot grid, concentric arcs in brand colour, and faint wordmark
  instead of the flat zinc gradient div

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor: unify campaign description rendering logic to prioritize details over description fields across project components

---------

Co-authored-by: Benjtalkshow <chinedubenj@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: add tabbed navigation to campaign page for overview, milestones, and supporters sections

* refactor: enhance milestone detail page with status-specific feedback views and improved header metadata

* feat: add polling to campaign query and improve cache invalidation across crowdfunding hooks

* feat(bounty): participant data layer (escrow client + hooks) (#643)

Add the builder/participant data layer to features/bounties, mirroring the
hackathon participant scope and reusing the shared escrow runner. The visible
builder UI (marketplace, detail, apply/submit/withdraw, my-bounties) consumes
this.

- participant-escrow-client: on-chain apply/submit/withdraw-application/
  withdraw-submission/contribute + participant op poll + submit-signed
  (the no-org-prefix /api/bounties/{id}/escrow/* routes)
- participant-client: public list/detail, v2 application records
  (apply/edit/withdraw/me), competition join/leave
- use-participant hooks: useBountiesList/useBounty/useMyBountyApplication,
  useApply/Edit/WithdrawApplication, useJoin/LeaveCompetition, and escrow-op
  hooks (useSubmitBounty/useWithdrawSubmission/useContributeToBounty/
  useApplyToBountyEscrow/useWithdrawApplicationEscrow) driven through the
  runner, default MANAGED
- use-escrow: EscrowOpScope is now organizer | participant; the runner routes
  op-poll/submit-signed to the participant URLs
- keys/types/index: participant query keys, type aliases, public exports

MyBountyApplication is hand-typed until boundless-nestjs #331 lands and codegen
runs; useMyBountyActivity is deferred until the participant dashboard (#332).

Closes #621

* feat(bounty): public bounty marketplace (discover/list) (#645)

* feat(bounty): participant data layer (escrow client + hooks)

Add the builder/participant data layer to features/bounties, mirroring the
hackathon participant scope and reusing the shared escrow runner. The visible
builder UI (marketplace, detail, apply/submit/withdraw, my-bounties) consumes
this.

- participant-escrow-client: on-chain apply/submit/withdraw-application/
  withdraw-submission/contribute + participant op poll + submit-signed
  (the no-org-prefix /api/bounties/{id}/escrow/* routes)
- participant-client: public list/detail, v2 application records
  (apply/edit/withdraw/me), competition join/leave
- use-participant hooks: useBountiesList/useBounty/useMyBountyApplication,
  useApply/Edit/WithdrawApplication, useJoin/LeaveCompetition, and escrow-op
  hooks (useSubmitBounty/useWithdrawSubmission/useContributeToBounty/
  useApplyToBountyEscrow/useWithdrawApplicationEscrow) driven through the
  runner, default MANAGED
- use-escrow: EscrowOpScope is now organizer | participant; the runner routes
  op-poll/submit-signed to the participant URLs
- keys/types/index: participant query keys, type aliases, public exports

MyBountyApplication is hand-typed until boundless-nestjs #331 lands and codegen
runs; useMyBountyActivity is deferred until the participant dashboard (#332).

Closes #621

* feat(bounty): public bounty marketplace (discover/list)

Replace the /coming-soon placeholder at /bounties with a real public
marketplace, mirroring the hackathon browse and wired to the participant
data layer (#621).

- route app/(landing)/bounties/page.tsx + bounties metadata entry
- BountiesPage: search + status + mode filters, infinite scroll,
  loading/empty/error states
- BountyCard: mode badge (plain label), status, reward, organization,
  application-window date; links to /bounties/[id]
- BountiesFiltersHeader + colocated useInfiniteBounties (infinite query
  over listBounties)

Status + search filter server-side; mode narrows client-side (the public
list endpoint doesn't filter on mode). Category filter and a card submission
deadline are omitted because BountyPublicDto exposes neither — small backend
follow-ups.

Closes #622

* feat(bounty): bounty detail page (/bounties/[id]) (#646)

* feat(bounty): participant data layer (escrow client + hooks)

Add the builder/participant data layer to features/bounties, mirroring the
hackathon participant scope and reusing the shared escrow runner. The visible
builder UI (marketplace, detail, apply/submit/withdraw, my-bounties) consumes
this.

- participant-escrow-client: on-chain apply/submit/withdraw-application/
  withdraw-submission/contribute + participant op poll + submit-signed
  (the no-org-prefix /api/bounties/{id}/escrow/* routes)
- participant-client: public list/detail, v2 application records
  (apply/edit/withdraw/me), competition join/leave
- use-participant hooks: useBountiesList/useBounty/useMyBountyApplication,
  useApply/Edit/WithdrawApplication, useJoin/LeaveCompetition, and escrow-op
  hooks (useSubmitBounty/useWithdrawSubmission/useContributeToBounty/
  useApplyToBountyEscrow/useWithdrawApplicationEscrow) driven through the
  runner, default MANAGED
- use-escrow: EscrowOpScope is now organizer | participant; the runner routes
  op-poll/submit-signed to the participant URLs
- keys/types/index: participant query keys, type aliases, public exports

MyBountyApplication is hand-typed until boundless-nestjs #331 lands and codegen
runs; useMyBountyActivity is deferred until the participant dashboard (#332).

Closes #621

* feat(bounty): public bounty marketplace (discover/list)

Replace the /coming-soon placeholder at /bounties with a real public
marketplace, mirroring the hackathon browse and wired to the participant
data layer (#621).

- route app/(landing)/bounties/page.tsx + bounties metadata entry
- BountiesPage: search + status + mode filters, infinite scroll,
  loading/empty/error states
- BountyCard: mode badge (plain label), status, reward, organization,
  application-window date; links to /bounties/[id]
- BountiesFiltersHeader + colocated useInfiniteBounties (infinite query
  over listBounties)

Status + search filter server-side; mode narrows client-side (the public
list endpoint doesn't filter on mode). Category filter and a card submission
deadline are omitted because BountyPublicDto exposes neither — small backend
follow-ups.

Closes #622

* feat(bounty): bounty detail page (/bounties/[id])

The builder hub: shows the bounty, the caller's status, and a mode-aware
entry CTA. Wired to the participant data layer (#621).

- route app/(landing)/bounties/[id]/page.tsx
- BountyDetail: markdown description, prize tiers, mode/status badges,
  organization, reward pool + eligibility sidebar (reputation minimum /
  application window / max applicants / shortlist); loading + not-found
- BountyEntryCta: mode-aware CTA — Claim (open+single), Join (open+
  competition), Apply (application). Gated/explained when not accepting,
  the application window closed, or already applied; shows the caller's
  application status via useMyBountyApplication

The actual entry execution (forms / on-chain op) ships in #624; the CTA is
gated + labeled and hands off to it. applicationCreditCost is not in
BountyPublicDto so it's omitted from the eligibility panel.

Closes #623

* feat(bounty): apply / join / claim flow + edit/withdraw (mode-aware) (#647)

Fill the entry execution the detail-page CTA hands off to (#623), wired to
the participant data layer (#621). Covers all six modes.

- applicationSchema: mode-aware zod validation + body builders (light:
  proposalShort 100-300 words + estimatedDays + <=3 links; full: proposalFull
  500-2000 words + qualifications >=50 chars + <=6 links + optional video)
- BountyApplicationForm: conditional fields per entry type with live word
  count; reused for create + edit
- BountyEntryDialog: mode-aware modal — Apply (POST v2/applications) / Edit
  (PATCH); Join (POST v2/competition/join); Claim (on-chain apply escrow op,
  MANAGED, with progress + reputation pre-check). Wallet-gated.
- BountyEntryCta: opens the dialog and, for an active application, exposes
  Edit + Withdraw (application), Leave (competition), or on-chain Withdraw
  (single claim) behind a two-step confirm

Closes #624

* feat(bounty): submit work (on-chain anchor) + withdraw submission (#649)

After entry (claim/join/selection) the builder submits their deliverable,
anchored on-chain via the participant escrow runner (#621). Mirrors the
hackathon submission anchor.

- BountySubmitPanel (detail sidebar, shown when eligible: claimed/joined/
  SELECTED/SHORTLISTED): contentUri deliverable input -> submit escrow op
  (useSubmitBounty, MANAGED) with anchor progress (preparing -> anchoring ->
  confirmed) + tx-hash explorer link
- Withdraw submission via useWithdrawSubmission behind a two-step confirm
- Wallet-gated; guarded by entry eligibility

Persistent submission state across reloads is session-local until the #332
my-submission read lands in the schema; the submission-deadline gate is
enforced on-chain (not in BountyPublicDto).

Closes #625

* feat(bounty): builder "my bounties" activity + rewards receipt (#651)

The builder's /me surfaces for bounty applications, submissions, and reward
receipts, consuming the participant dashboard (#332) + earnings (#335).

- data layer: useMyBountyApplications / useMyBountySubmissions (the deferred
  useMyBountyActivity) via the legacy axios api (hand-typed rows, retry:false,
  degrading to empty until #332 lands in the schema)
- /me/bounties page: Applications + Submissions tabs with status/progress
  badges; won submissions show the reward amount + a payout tx-hash link;
  rows link to the detail page
- sidebar: "My Bounties" nav entry
- /me/earnings: the page already renders breakdown.bounties + activities
  generically (so #335 surfaces them); add a "View tx" link to reward
  activities (txHash cast until codegen)

Closes #626

* ci: auto-close linked issues on merge to any base branch (#652)

GitHub's built-in Closes/Fixes/Resolves auto-close only fires for PRs
merged into the default branch. Feature PRs here merge into integration
branches (feat/t-replace, etc.), leaving linked issues open. This adds a
pull_request_target workflow that parses the merged PR body and closes
the referenced same-repo issues on any base branch.

* feat(bounty): codegen refresh + retire hand-typed participant casts (#627) (#653)

The participant gap endpoints (applications/me, my-activity, results) have
landed in v2, so regenerate the OpenAPI schema and replace the two
hand-typed casts (MyBountyApplication, my-activity dashboard rows) with
their generated DTO aliases. Refresh openapi.snapshot.json so offline/CI
codegen matches. Nav entries (marketplace + /me sidebar) already shipped.

* feat: add template selection to hackathon generation dialog with new hook and UI component

* feat(bounty): submission page, marketplace redesign, and organizer requirements (#662)

* feat(bounty): submission metadata types, category filter, and wizard requirement toggles

Refresh the generated OpenAPI schema for the new public-bounty fields
(claimedBy, category, submissionDeadline, submissionRequirements) and the
submit-op metadata. Add the category query param to the marketplace list
client, the per-bounty my-submission read + hook, and the organizer
requirement toggles in the Configure wizard's submission step. Flatten the
category reputation baseline to 0 for testing and let the wizard accept a
0 floor.

* feat(bounty): marketplace card redesign, category tabs, and detail display

Bounty cards now show the organizer logo, category, a live due-date
countdown, and the USDC token logo (title only, no markdown bleed). Add a
category tab bar to the marketplace and mirror the same details on the
detail page, plus a mode-explainer tooltip. Single-claim bounties render a
'Claimed by' card linking to the claimant profile, and the application
withdraw button is gated while a submission is anchored.

* feat(bounty): dedicated submit page with metadata and media upload

Replace the single-input submit panel with a /bounties/[id]/submit page:
primary submission link plus optional documentation, tweet, and demo video
links and a drag-and-drop media uploader. Required fields follow the
bounty's organizer-configured requirements; on success it returns to the
detail page. The sidebar panel now routes here (new tab) and reflects the
submitted/withdraw state.

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Nnaji Benjamin <60315147+Benjtalkshow@users.noreply.github.com>
Co-authored-by: Benjtalkshow <chinedubenj@gmail.com>
0xdevcollins added a commit that referenced this pull request Jun 30, 2026
…unding features (#665)

* feat: integrate treasury management features and refactor hackathon orchestration and API client architecture.

* chore: update package-lock.json dependencies

* chore: update pre-push husky hook to perform full type-checks and production builds

* refactor: remove DevelopmentStatusModal from global layout

* feat: task-first Winners page, judging UX, private access, treasury receipts/send

Winners: new task-first Winners section (pick winner per prize with engine default, inline stacking confirm, deliberate 'Don't award' + unawarded-funds acknowledgement); /rewards redirects to /winners; staged Pick -> Confirm -> Pay.

Judging: slimmed Results tab to read-only standings + 'Go to Winners'; criterionId name fix; AI scorecards, recommendation thresholds, CSV judge import, tracks + custom questions wizard sections; validation + empty-state polish.

Public: private + password access gate, community links, card private badge. Treasury: receipts + Send funds. Removed the stacking toggle from prize setup.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(bounty): ModeTab + SubmissionModelTab for the Configure wizard (#599) (#611)

The net-new bounty UI with no hackathon analog: the two-axis mode picker and
the mode-conditional submission settings that drive all six combinations.

- modeSchema.ts: plain taxonomy unions (entryType x claimType), the
  computeBountyModeLabel helper, and getModeFields — the mode -> field matrix
  derived functionally from the publish gate (validateTwoAxisMode) so it cannot
  drift from the backend.
- submissionModelSchema.ts: makeSubmissionModelSchema(mode), a mode-aware Zod
  factory whose required fields and the >=2 floors (maxApplicants for open
  competition, shortlistSize for application competition) mirror the server gate.
- ModeTab.tsx: entry x claim picker, a winners stepper (1-3) for competitions,
  and a live computed mode label.
- SubmissionModelTab.tsx: renders each field per the matrix (required / optional
  / hidden) and shows submissionVisibility read-only, forced by the mode
  (HIDDEN_UNTIL_DEADLINE for competitions).

Standalone components (props: mode, onSave, onContinue, initialData, isLoading);
they wire into the wizard shell + routes in #597 / #598.

* feat(bounty): features/bounties data layer (types, keys, draft + escrow) (#596) (#612)

Adds the features/bounties/ data layer for the v1 app, mirroring
features/hackathons/. REST-only via the typed openapi-fetch client; every
server shape is aliased from the backend-generated schema so it cannot drift.

- types.ts: aliases the generated draft + escrow DTOs (BountyDraft,
  UpdateBountyDraftBody, the four section types, BountyEscrowOpResponse,
  PublishBountyEscrowRequest, ...). Derives the two-axis taxonomy from the
  generated mode DTO, superseding the local stubs in the ModeTab.
- api/keys.ts: bountyKeys factory.
- api/draft-client.ts + use-draft.ts: imperative CRUD plus the
  useDraft / useDraftList / useCreateDraft / useUpdateDraft / useDeleteDraft
  hooks against /organizations/{organizationId}/bounties/draft[/{id}] + /drafts.
- api/escrow-client.ts + use-escrow.ts: organizer escrow calls (publish /
  cancel / select-winners / submit-signed / poll) plus useEscrowOp +
  useEscrowOpRunner, mirroring the hackathon machinery (MANAGED polls; EXTERNAL
  signs -> submit -> poll) bounty-scoped.
- index.ts: public surface.

Regenerates lib/api/generated/schema.d.ts from the v2 backend so the bounty
draft paths/DTOs are present.

* feat(bounty): wizard shell + step/draft machinery (#598) (#613)

* feat(bounty): features/bounties data layer (types, keys, draft + escrow) (#596)

Adds the features/bounties/ data layer for the v1 app, mirroring
features/hackathons/. REST-only via the typed openapi-fetch client; every
server shape is aliased from the backend-generated schema so it cannot drift.

- types.ts: aliases the generated draft + escrow DTOs (BountyDraft,
  UpdateBountyDraftBody, the four section types, BountyEscrowOpResponse,
  PublishBountyEscrowRequest, ...). Derives the two-axis taxonomy from the
  generated mode DTO, superseding the local stubs in the ModeTab.
- api/keys.ts: bountyKeys factory.
- api/draft-client.ts + use-draft.ts: imperative CRUD plus the
  useDraft / useDraftList / useCreateDraft / useUpdateDraft / useDeleteDraft
  hooks against /organizations/{organizationId}/bounties/draft[/{id}] + /drafts.
- api/escrow-client.ts + use-escrow.ts: organizer escrow calls (publish /
  cancel / select-winners / submit-signed / poll) plus useEscrowOp +
  useEscrowOpRunner, mirroring the hackathon machinery (MANAGED polls; EXTERNAL
  signs -> submit -> poll) bounty-scoped.
- index.ts: public surface.

Regenerates lib/api/generated/schema.d.ts from the v2 backend so the bounty
draft paths/DTOs are present.

* feat(bounty): wizard shell + step/draft machinery (#598)

Adds the bounty Configure wizard orchestrator and its step + draft state,
mirroring the hackathon wizard. No AI assist.

- components/organization/bounties/new/constants.ts: StepKey
  (scope/mode/submission/reward/review), STEP_ORDER, BountyFormData, and
  isBountyStepDataValid.
- hooks/use-bounty-steps.ts: URL ?step= navigation (free-roam) with a
  presentational step-status map.
- hooks/use-bounty-draft.ts: lazy create (ensureDraftId) then per-section PATCH,
  resume via useDraft, and transformBountyFromApi (sections -> form state;
  winnerCount derived from prize tiers, ISO dates trimmed for the inputs).
- components/organization/bounties/new/NewBountyTab.tsx: orchestrator wiring
  steps + draft + per-step save, persisting ?draftId= for resume, and threading
  the chosen mode from ModeTab into SubmissionModelTab.

Scope/Reward/Review tabs (#600) and the publish + funding flow (#601) are left
as marked placeholders with their save/navigate/draftId seams in place; this
satisfies the acceptance criteria (navigate, autosave, resume) without
speculative publish UI that depends on the unbuilt publish hook.

* feat(bounty): Scope + Reward + Review tabs and Zod schemas (#600) (#614)

Completes the editable surface of the bounty Configure wizard, dropping the
three remaining tabs into the seams the shell (#598) left.

- tabs/schemas/scopeSchema.ts: title, description, optional GitHub issue
  url/number, optional project/window.
- tabs/schemas/rewardSchema.ts: makeRewardSchema(claimType) — exactly one tier
  for single claim, 1-3 for a competition; amounts > 0, unique positions
  including position 1 (mirrors the publish gate's deriveWinnerDistribution).
- lib/utils/bounty-escrow.ts: adapts the bounty reward shape to reuse the
  hackathon prize-pool math (getTotalPrizePoolForFunding, buildWinnerDistribution,
  2.5% PLATFORM_FEE) rather than duplicating it.
- tabs/ScopeTab.tsx: scope form.
- tabs/RewardTab.tsx: currency + mode-driven prize tiers (field array sized to
  the winner count) with a live prize-pool / fee / total preview.
- tabs/ReviewTab.tsx: per-section summary, validation summary, funding totals,
  and a publish CTA disabled until every section validates.
- NewBountyTab.tsx + constants.ts: wire the three tabs into the wizard; the form
  snapshot now uses the per-tab form schema types.

Reward currency is collected in the Reward step (the backend section that
persists it) rather than Scope, so it round-trips. The publish action is a
placeholder pending the escrow publish flow (#601); the disabled-until-valid
gate is wired here.

* feat(bounty): use-bounty-publish (escrow publish via shared runner) (#601) (#615)

* feat(bounty): Scope + Reward + Review tabs and Zod schemas (#600)

Completes the editable surface of the bounty Configure wizard, dropping the
three remaining tabs into the seams the shell (#598) left.

- tabs/schemas/scopeSchema.ts: title, description, optional GitHub issue
  url/number, optional project/window.
- tabs/schemas/rewardSchema.ts: makeRewardSchema(claimType) — exactly one tier
  for single claim, 1-3 for a competition; amounts > 0, unique positions
  including position 1 (mirrors the publish gate's deriveWinnerDistribution).
- lib/utils/bounty-escrow.ts: adapts the bounty reward shape to reuse the
  hackathon prize-pool math (getTotalPrizePoolForFunding, buildWinnerDistribution,
  2.5% PLATFORM_FEE) rather than duplicating it.
- tabs/ScopeTab.tsx: scope form.
- tabs/RewardTab.tsx: currency + mode-driven prize tiers (field array sized to
  the winner count) with a live prize-pool / fee / total preview.
- tabs/ReviewTab.tsx: per-section summary, validation summary, funding totals,
  and a publish CTA disabled until every section validates.
- NewBountyTab.tsx + constants.ts: wire the three tabs into the wizard; the form
  snapshot now uses the per-tab form schema types.

Reward currency is collected in the Reward step (the backend section that
persists it) rather than Scope, so it round-trips. The publish action is a
placeholder pending the escrow publish flow (#601); the disabled-until-valid
gate is wired here.

* feat(bounty): use-bounty-publish (escrow publish via shared runner) (#601)

Wires the bounty publish action, mirroring use-hackathon-publish.

- hooks/use-bounty-publish.ts: builds PublishBountyEscrowDto (ownerAddress,
  tokenAddress via getTokenAddress('USDC'), budget = sum of tier amounts,
  submissionDeadline as unix from the draft deadline, applicationCreditCost,
  winnerDistribution via the shared buildBountyWinnerDistribution, fundingMode)
  and drives it with useEscrowOpRunner: MANAGED returns PENDING_CONFIRM then
  polls; EXTERNAL signs the returned XDR via signXdrWithKit then submits + polls.
  On COMPLETED the bounty has moved draft_awaiting_funding -> open. Pre-flight
  resumes an in-flight op, short-circuits an already-published bounty, and runs a
  MANAGED USDC balance check (pool + 2.5% fee).
- NewBountyTab.tsx: replace the Review placeholder with the real publish() and
  wire isPublishing into the CTA.

Treasury funding (sourceWalletId) is omitted until the backend treasury-parity
issue (boundless-nestjs #314) lands; MANAGED + EXTERNAL are supported. The
funding-source picker + progress modal remain a follow-up; the hook exposes the
escrow phase/error/txHash they need.

* feat(bounty): routes + organization bounty list page (#597) (#616)

Adds the organizer bounty routes, mirroring the hackathon route tree, and the
published-list data needed by the list page.

- app/(landing)/organizations/[id]/bounties/page.tsx: list page with a Drafts
  section (resume links + status badges + mode label / section count) and a
  Published section (status badges + reward), plus a "Host a bounty" CTA.
- .../bounties/new/page.tsx: renders <NewBountyTab organizationId={id} />.
- .../bounties/drafts/[draftId]/page.tsx: renders
  <NewBountyTab organizationId={id} draftId={draftId} />.
- features/bounties/api/core.ts + use-bounties.ts: listOrganizationBounties +
  useOrganizationBounties for the root list (the backend root GET has no
  response DTO, so the row shape is projected to OrganizationBountyListItem).

The pages mount the existing wizard shell (#598); the list separates drafts
(draft / draft_awaiting_funding) from published bounties so they don't
double-list.

* feat(bounty): sidebar nav entry + Post Bounty quick action (#602) (#617)

Adds a Bounties menu item (/organizations/{orgId}/bounties) and a Post Bounty
quick action (/organizations/{orgId}/bounties/new) to OrganizationSidebar, so
organizers can reach the bounty list + Configure wizard.

Codegen reconcile: re-ran npm run codegen against the v2 backend; the committed
lib/api/generated/schema.d.ts already matches (BountyDraftResponseDto +
UpdateBountyDraftDto present, no drift), so no schema change is needed.

* feat(bounty): wizard enhancements + hackathon-style org bounty list (#618)

* feat(bounty): wizard enhancements (resources step, currency, reputation, nav)

- Resources: new optional Resources step (links + PDF/DOC/PPT/MD uploads),
  mirroring the hackathon resources tab; never blocks publish. Reuses a now
  configurable ResourceFileUpload (folder/tags/accepted types props; unique
  input id per row).
- Reward currency: dropdown of USDC (default) / XLM (disabled) with real token
  logos, replacing the free-text field.
- Reputation: per-category minimum floor (development highest); the organizer
  can raise it but not drop below the category baseline.
- Navigation: Back button on every step after the first.
- Scope: category chips + searchable country dropdown with flags + markdown
  description; GitHub issue URL required only for development.
- Publish: redirect to the organizer's bounty list once publish finalizes.
- Dev-only "Fill with mock" button to populate every section at once.

* feat(bounty): hackathon-style org bounty list + delete-draft confirm

- Rebuild the organization bounty list page in the hackathon style: sticky
  header with stats, Published/Drafts tabs, search + sort, and a banner-less
  reward-focused card grid (draft cards show a progress bar + resume link).
- Deleting a draft now opens a confirmation modal (DeleteBountyDraftDialog)
  instead of deleting on the first click.
- Expose `_count.submissions` on the org bounty list item for the cards.

* Feat/crowdfunding (#620)

* feat(bounty): features/bounties data layer (types, keys, draft + escrow) (#596)

Adds the features/bounties/ data layer for the v1 app, mirroring
features/hackathons/. REST-only via the typed openapi-fetch client; every
server shape is aliased from the backend-generated schema so it cannot drift.

- types.ts: aliases the generated draft + escrow DTOs (BountyDraft,
  UpdateBountyDraftBody, the four section types, BountyEscrowOpResponse,
  PublishBountyEscrowRequest, ...). Derives the two-axis taxonomy from the
  generated mode DTO, superseding the local stubs in the ModeTab.
- api/keys.ts: bountyKeys factory.
- api/draft-client.ts + use-draft.ts: imperative CRUD plus the
  useDraft / useDraftList / useCreateDraft / useUpdateDraft / useDeleteDraft
  hooks against /organizations/{organizationId}/bounties/draft[/{id}] + /drafts.
- api/escrow-client.ts + use-escrow.ts: organizer escrow calls (publish /
  cancel / select-winners / submit-signed / poll) plus useEscrowOp +
  useEscrowOpRunner, mirroring the hackathon machinery (MANAGED polls; EXTERNAL
  signs -> submit -> poll) bounty-scoped.
- index.ts: public surface.

Regenerates lib/api/generated/schema.d.ts from the v2 backend so the bounty
draft paths/DTOs are present.

* feat(bounty): wizard shell + step/draft machinery (#598)

Adds the bounty Configure wizard orchestrator and its step + draft state,
mirroring the hackathon wizard. No AI assist.

- components/organization/bounties/new/constants.ts: StepKey
  (scope/mode/submission/reward/review), STEP_ORDER, BountyFormData, and
  isBountyStepDataValid.
- hooks/use-bounty-steps.ts: URL ?step= navigation (free-roam) with a
  presentational step-status map.
- hooks/use-bounty-draft.ts: lazy create (ensureDraftId) then per-section PATCH,
  resume via useDraft, and transformBountyFromApi (sections -> form state;
  winnerCount derived from prize tiers, ISO dates trimmed for the inputs).
- components/organization/bounties/new/NewBountyTab.tsx: orchestrator wiring
  steps + draft + per-step save, persisting ?draftId= for resume, and threading
  the chosen mode from ModeTab into SubmissionModelTab.

Scope/Reward/Review tabs (#600) and the publish + funding flow (#601) are left
as marked placeholders with their save/navigate/draftId seams in place; this
satisfies the acceptance criteria (navigate, autosave, resume) without
speculative publish UI that depends on the unbuilt publish hook.

* feat: implement multi-step crowdfunding campaign wizard with milestone management

* feat(crowdfunding): v2 public pages, builder dashboard, milestone tracking

- Redesigned public listing (ProjectCard) and detail page with proper
  lifecycle states, voting panel, contributor list, and fully-funded detection
- Added public milestone list + detail pages under /crowdfunding/[slug]/milestones
- Builder per-campaign management: tabbed layout (overview / milestones /
  contributions) with shared header showing milestone X/Y progress and
  Fully Funded badge once fundingRaised >= fundingGoal
- Milestone status sourced from milestoneState() utility: claimedAt-based
  "paid out" detection replaces stale reviewStatus === 'completed' checks
- CampaignStatusBanner: shows milestone delivery bar and Fully Funded label
  during the FUNDING phase when goal is reached
- milestones-metrics: completedAmount correctly sums paid-out milestones;
  inProgress checks SUBMITTED/UNDER_REVIEW enum values
- ProjectCard: switches from funding bar to milestone X/Y bar on fully funded;
  footer and status badge update to Fully Funded (green)
- lib/crowdfunding/status.ts: single source of truth for all campaign and
  milestone status copy and tone

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: update lockfile dependencies for package-lock.json

---------

Co-authored-by: Benjtalkshow <chinedubenj@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* Feat/crowdfunding (#642)

* feat(bounty): features/bounties data layer (types, keys, draft + escrow) (#596)

Adds the features/bounties/ data layer for the v1 app, mirroring
features/hackathons/. REST-only via the typed openapi-fetch client; every
server shape is aliased from the backend-generated schema so it cannot drift.

- types.ts: aliases the generated draft + escrow DTOs (BountyDraft,
  UpdateBountyDraftBody, the four section types, BountyEscrowOpResponse,
  PublishBountyEscrowRequest, ...). Derives the two-axis taxonomy from the
  generated mode DTO, superseding the local stubs in the ModeTab.
- api/keys.ts: bountyKeys factory.
- api/draft-client.ts + use-draft.ts: imperative CRUD plus the
  useDraft / useDraftList / useCreateDraft / useUpdateDraft / useDeleteDraft
  hooks against /organizations/{organizationId}/bounties/draft[/{id}] + /drafts.
- api/escrow-client.ts + use-escrow.ts: organizer escrow calls (publish /
  cancel / select-winners / submit-signed / poll) plus useEscrowOp +
  useEscrowOpRunner, mirroring the hackathon machinery (MANAGED polls; EXTERNAL
  signs -> submit -> poll) bounty-scoped.
- index.ts: public surface.

Regenerates lib/api/generated/schema.d.ts from the v2 backend so the bounty
draft paths/DTOs are present.

* feat(bounty): wizard shell + step/draft machinery (#598)

Adds the bounty Configure wizard orchestrator and its step + draft state,
mirroring the hackathon wizard. No AI assist.

- components/organization/bounties/new/constants.ts: StepKey
  (scope/mode/submission/reward/review), STEP_ORDER, BountyFormData, and
  isBountyStepDataValid.
- hooks/use-bounty-steps.ts: URL ?step= navigation (free-roam) with a
  presentational step-status map.
- hooks/use-bounty-draft.ts: lazy create (ensureDraftId) then per-section PATCH,
  resume via useDraft, and transformBountyFromApi (sections -> form state;
  winnerCount derived from prize tiers, ISO dates trimmed for the inputs).
- components/organization/bounties/new/NewBountyTab.tsx: orchestrator wiring
  steps + draft + per-step save, persisting ?draftId= for resume, and threading
  the chosen mode from ModeTab into SubmissionModelTab.

Scope/Reward/Review tabs (#600) and the publish + funding flow (#601) are left
as marked placeholders with their save/navigate/draftId seams in place; this
satisfies the acceptance criteria (navigate, autosave, resume) without
speculative publish UI that depends on the unbuilt publish hook.

* feat: implement multi-step crowdfunding campaign wizard with milestone management

* feat(crowdfunding): v2 public pages, builder dashboard, milestone tracking

- Redesigned public listing (ProjectCard) and detail page with proper
  lifecycle states, voting panel, contributor list, and fully-funded detection
- Added public milestone list + detail pages under /crowdfunding/[slug]/milestones
- Builder per-campaign management: tabbed layout (overview / milestones /
  contributions) with shared header showing milestone X/Y progress and
  Fully Funded badge once fundingRaised >= fundingGoal
- Milestone status sourced from milestoneState() utility: claimedAt-based
  "paid out" detection replaces stale reviewStatus === 'completed' checks
- CampaignStatusBanner: shows milestone delivery bar and Fully Funded label
  during the FUNDING phase when goal is reached
- milestones-metrics: completedAmount correctly sums paid-out milestones;
  inProgress checks SUBMITTED/UNDER_REVIEW enum values
- ProjectCard: switches from funding bar to milestone X/Y bar on fully funded;
  footer and status badge update to Fully Funded (green)
- lib/crowdfunding/status.ts: single source of truth for all campaign and
  milestone status copy and tone

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: update lockfile dependencies for package-lock.json

* refactor: standardize API error extraction to support array-based messages across crowdfunding components

* refactor: restructure StoryStep inputs, enable sidebar navigation, and update campaign wizard validation logic

---------

Co-authored-by: Benjtalkshow <chinedubenj@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* Feat/crowdfunding (#644)

* feat(bounty): features/bounties data layer (types, keys, draft + escrow) (#596)

Adds the features/bounties/ data layer for the v1 app, mirroring
features/hackathons/. REST-only via the typed openapi-fetch client; every
server shape is aliased from the backend-generated schema so it cannot drift.

- types.ts: aliases the generated draft + escrow DTOs (BountyDraft,
  UpdateBountyDraftBody, the four section types, BountyEscrowOpResponse,
  PublishBountyEscrowRequest, ...). Derives the two-axis taxonomy from the
  generated mode DTO, superseding the local stubs in the ModeTab.
- api/keys.ts: bountyKeys factory.
- api/draft-client.ts + use-draft.ts: imperative CRUD plus the
  useDraft / useDraftList / useCreateDraft / useUpdateDraft / useDeleteDraft
  hooks against /organizations/{organizationId}/bounties/draft[/{id}] + /drafts.
- api/escrow-client.ts + use-escrow.ts: organizer escrow calls (publish /
  cancel / select-winners / submit-signed / poll) plus useEscrowOp +
  useEscrowOpRunner, mirroring the hackathon machinery (MANAGED polls; EXTERNAL
  signs -> submit -> poll) bounty-scoped.
- index.ts: public surface.

Regenerates lib/api/generated/schema.d.ts from the v2 backend so the bounty
draft paths/DTOs are present.

* feat(bounty): wizard shell + step/draft machinery (#598)

Adds the bounty Configure wizard orchestrator and its step + draft state,
mirroring the hackathon wizard. No AI assist.

- components/organization/bounties/new/constants.ts: StepKey
  (scope/mode/submission/reward/review), STEP_ORDER, BountyFormData, and
  isBountyStepDataValid.
- hooks/use-bounty-steps.ts: URL ?step= navigation (free-roam) with a
  presentational step-status map.
- hooks/use-bounty-draft.ts: lazy create (ensureDraftId) then per-section PATCH,
  resume via useDraft, and transformBountyFromApi (sections -> form state;
  winnerCount derived from prize tiers, ISO dates trimmed for the inputs).
- components/organization/bounties/new/NewBountyTab.tsx: orchestrator wiring
  steps + draft + per-step save, persisting ?draftId= for resume, and threading
  the chosen mode from ModeTab into SubmissionModelTab.

Scope/Reward/Review tabs (#600) and the publish + funding flow (#601) are left
as marked placeholders with their save/navigate/draftId seams in place; this
satisfies the acceptance criteria (navigate, autosave, resume) without
speculative publish UI that depends on the unbuilt publish hook.

* feat: implement multi-step crowdfunding campaign wizard with milestone management

* feat(crowdfunding): v2 public pages, builder dashboard, milestone tracking

- Redesigned public listing (ProjectCard) and detail page with proper
  lifecycle states, voting panel, contributor list, and fully-funded detection
- Added public milestone list + detail pages under /crowdfunding/[slug]/milestones
- Builder per-campaign management: tabbed layout (overview / milestones /
  contributions) with shared header showing milestone X/Y progress and
  Fully Funded badge once fundingRaised >= fundingGoal
- Milestone status sourced from milestoneState() utility: claimedAt-based
  "paid out" detection replaces stale reviewStatus === 'completed' checks
- CampaignStatusBanner: shows milestone delivery bar and Fully Funded label
  during the FUNDING phase when goal is reached
- milestones-metrics: completedAmount correctly sums paid-out milestones;
  inProgress checks SUBMITTED/UNDER_REVIEW enum values
- ProjectCard: switches from funding bar to milestone X/Y bar on fully funded;
  footer and status badge update to Fully Funded (green)
- lib/crowdfunding/status.ts: single source of truth for all campaign and
  milestone status copy and tone

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: update lockfile dependencies for package-lock.json

* refactor: standardize API error extraction to support array-based messages across crowdfunding components

* refactor: restructure StoryStep inputs, enable sidebar navigation, and update campaign wizard validation logic

* feat: replace textarea with AnnouncementEditor and add markdown rendering for campaign project details

---------

Co-authored-by: Benjtalkshow <chinedubenj@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* Feat/crowdfunding (#648)

* feat(bounty): features/bounties data layer (types, keys, draft + escrow) (#596)

Adds the features/bounties/ data layer for the v1 app, mirroring
features/hackathons/. REST-only via the typed openapi-fetch client; every
server shape is aliased from the backend-generated schema so it cannot drift.

- types.ts: aliases the generated draft + escrow DTOs (BountyDraft,
  UpdateBountyDraftBody, the four section types, BountyEscrowOpResponse,
  PublishBountyEscrowRequest, ...). Derives the two-axis taxonomy from the
  generated mode DTO, superseding the local stubs in the ModeTab.
- api/keys.ts: bountyKeys factory.
- api/draft-client.ts + use-draft.ts: imperative CRUD plus the
  useDraft / useDraftList / useCreateDraft / useUpdateDraft / useDeleteDraft
  hooks against /organizations/{organizationId}/bounties/draft[/{id}] + /drafts.
- api/escrow-client.ts + use-escrow.ts: organizer escrow calls (publish /
  cancel / select-winners / submit-signed / poll) plus useEscrowOp +
  useEscrowOpRunner, mirroring the hackathon machinery (MANAGED polls; EXTERNAL
  signs -> submit -> poll) bounty-scoped.
- index.ts: public surface.

Regenerates lib/api/generated/schema.d.ts from the v2 backend so the bounty
draft paths/DTOs are present.

* feat(bounty): wizard shell + step/draft machinery (#598)

Adds the bounty Configure wizard orchestrator and its step + draft state,
mirroring the hackathon wizard. No AI assist.

- components/organization/bounties/new/constants.ts: StepKey
  (scope/mode/submission/reward/review), STEP_ORDER, BountyFormData, and
  isBountyStepDataValid.
- hooks/use-bounty-steps.ts: URL ?step= navigation (free-roam) with a
  presentational step-status map.
- hooks/use-bounty-draft.ts: lazy create (ensureDraftId) then per-section PATCH,
  resume via useDraft, and transformBountyFromApi (sections -> form state;
  winnerCount derived from prize tiers, ISO dates trimmed for the inputs).
- components/organization/bounties/new/NewBountyTab.tsx: orchestrator wiring
  steps + draft + per-step save, persisting ?draftId= for resume, and threading
  the chosen mode from ModeTab into SubmissionModelTab.

Scope/Reward/Review tabs (#600) and the publish + funding flow (#601) are left
as marked placeholders with their save/navigate/draftId seams in place; this
satisfies the acceptance criteria (navigate, autosave, resume) without
speculative publish UI that depends on the unbuilt publish hook.

* feat: implement multi-step crowdfunding campaign wizard with milestone management

* feat(crowdfunding): v2 public pages, builder dashboard, milestone tracking

- Redesigned public listing (ProjectCard) and detail page with proper
  lifecycle states, voting panel, contributor list, and fully-funded detection
- Added public milestone list + detail pages under /crowdfunding/[slug]/milestones
- Builder per-campaign management: tabbed layout (overview / milestones /
  contributions) with shared header showing milestone X/Y progress and
  Fully Funded badge once fundingRaised >= fundingGoal
- Milestone status sourced from milestoneState() utility: claimedAt-based
  "paid out" detection replaces stale reviewStatus === 'completed' checks
- CampaignStatusBanner: shows milestone delivery bar and Fully Funded label
  during the FUNDING phase when goal is reached
- milestones-metrics: completedAmount correctly sums paid-out milestones;
  inProgress checks SUBMITTED/UNDER_REVIEW enum values
- ProjectCard: switches from funding bar to milestone X/Y bar on fully funded;
  footer and status badge update to Fully Funded (green)
- lib/crowdfunding/status.ts: single source of truth for all campaign and
  milestone status copy and tone

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: update lockfile dependencies for package-lock.json

* refactor: standardize API error extraction to support array-based messages across crowdfunding components

* refactor: restructure StoryStep inputs, enable sidebar navigation, and update campaign wizard validation logic

* feat: replace textarea with AnnouncementEditor and add markdown rendering for campaign project details

* fix: useCampaign routes UUID params to fetchCampaignById

Post-create redirect lands on /me/crowdfunding/{uuid}. The hook was
always calling the slug endpoint which rejected UUIDs. Now detects
UUID format and uses the correct /api/crowdfunding/{id} endpoint.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: auth-gate voting/contribute + branded fallback banner

- VotePanel: unauthenticated users see "Sign in to vote" instead of
  the yes/no buttons
- Public page: "Back this project" replaced with "Sign in to back this
  project" link for unauthenticated visitors
- Fallback banner (no banner set): full-height Boundless-branded SVG
  with dot grid, concentric arcs in brand colour, and faint wordmark
  instead of the flat zinc gradient div

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Benjtalkshow <chinedubenj@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* Feat/crowdfunding (#650)

* feat(bounty): features/bounties data layer (types, keys, draft + escrow) (#596)

Adds the features/bounties/ data layer for the v1 app, mirroring
features/hackathons/. REST-only via the typed openapi-fetch client; every
server shape is aliased from the backend-generated schema so it cannot drift.

- types.ts: aliases the generated draft + escrow DTOs (BountyDraft,
  UpdateBountyDraftBody, the four section types, BountyEscrowOpResponse,
  PublishBountyEscrowRequest, ...). Derives the two-axis taxonomy from the
  generated mode DTO, superseding the local stubs in the ModeTab.
- api/keys.ts: bountyKeys factory.
- api/draft-client.ts + use-draft.ts: imperative CRUD plus the
  useDraft / useDraftList / useCreateDraft / useUpdateDraft / useDeleteDraft
  hooks against /organizations/{organizationId}/bounties/draft[/{id}] + /drafts.
- api/escrow-client.ts + use-escrow.ts: organizer escrow calls (publish /
  cancel / select-winners / submit-signed / poll) plus useEscrowOp +
  useEscrowOpRunner, mirroring the hackathon machinery (MANAGED polls; EXTERNAL
  signs -> submit -> poll) bounty-scoped.
- index.ts: public surface.

Regenerates lib/api/generated/schema.d.ts from the v2 backend so the bounty
draft paths/DTOs are present.

* feat(bounty): wizard shell + step/draft machinery (#598)

Adds the bounty Configure wizard orchestrator and its step + draft state,
mirroring the hackathon wizard. No AI assist.

- components/organization/bounties/new/constants.ts: StepKey
  (scope/mode/submission/reward/review), STEP_ORDER, BountyFormData, and
  isBountyStepDataValid.
- hooks/use-bounty-steps.ts: URL ?step= navigation (free-roam) with a
  presentational step-status map.
- hooks/use-bounty-draft.ts: lazy create (ensureDraftId) then per-section PATCH,
  resume via useDraft, and transformBountyFromApi (sections -> form state;
  winnerCount derived from prize tiers, ISO dates trimmed for the inputs).
- components/organization/bounties/new/NewBountyTab.tsx: orchestrator wiring
  steps + draft + per-step save, persisting ?draftId= for resume, and threading
  the chosen mode from ModeTab into SubmissionModelTab.

Scope/Reward/Review tabs (#600) and the publish + funding flow (#601) are left
as marked placeholders with their save/navigate/draftId seams in place; this
satisfies the acceptance criteria (navigate, autosave, resume) without
speculative publish UI that depends on the unbuilt publish hook.

* feat: implement multi-step crowdfunding campaign wizard with milestone management

* feat(crowdfunding): v2 public pages, builder dashboard, milestone tracking

- Redesigned public listing (ProjectCard) and detail page with proper
  lifecycle states, voting panel, contributor list, and fully-funded detection
- Added public milestone list + detail pages under /crowdfunding/[slug]/milestones
- Builder per-campaign management: tabbed layout (overview / milestones /
  contributions) with shared header showing milestone X/Y progress and
  Fully Funded badge once fundingRaised >= fundingGoal
- Milestone status sourced from milestoneState() utility: claimedAt-based
  "paid out" detection replaces stale reviewStatus === 'completed' checks
- CampaignStatusBanner: shows milestone delivery bar and Fully Funded label
  during the FUNDING phase when goal is reached
- milestones-metrics: completedAmount correctly sums paid-out milestones;
  inProgress checks SUBMITTED/UNDER_REVIEW enum values
- ProjectCard: switches from funding bar to milestone X/Y bar on fully funded;
  footer and status badge update to Fully Funded (green)
- lib/crowdfunding/status.ts: single source of truth for all campaign and
  milestone status copy and tone

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: update lockfile dependencies for package-lock.json

* refactor: standardize API error extraction to support array-based messages across crowdfunding components

* refactor: restructure StoryStep inputs, enable sidebar navigation, and update campaign wizard validation logic

* feat: replace textarea with AnnouncementEditor and add markdown rendering for campaign project details

* fix: useCampaign routes UUID params to fetchCampaignById

Post-create redirect lands on /me/crowdfunding/{uuid}. The hook was
always calling the slug endpoint which rejected UUIDs. Now detects
UUID format and uses the correct /api/crowdfunding/{id} endpoint.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: auth-gate voting/contribute + branded fallback banner

- VotePanel: unauthenticated users see "Sign in to vote" instead of
  the yes/no buttons
- Public page: "Back this project" replaced with "Sign in to back this
  project" link for unauthenticated visitors
- Fallback banner (no banner set): full-height Boundless-branded SVG
  with dot grid, concentric arcs in brand colour, and faint wordmark
  instead of the flat zinc gradient div

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor: unify campaign description rendering logic to prioritize details over description fields across project components

---------

Co-authored-by: Benjtalkshow <chinedubenj@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: add tabbed navigation to campaign page for overview, milestones, and supporters sections

* refactor: enhance milestone detail page with status-specific feedback views and improved header metadata

* feat: add polling to campaign query and improve cache invalidation across crowdfunding hooks

* feat(bounty): participant data layer (escrow client + hooks) (#643)

Add the builder/participant data layer to features/bounties, mirroring the
hackathon participant scope and reusing the shared escrow runner. The visible
builder UI (marketplace, detail, apply/submit/withdraw, my-bounties) consumes
this.

- participant-escrow-client: on-chain apply/submit/withdraw-application/
  withdraw-submission/contribute + participant op poll + submit-signed
  (the no-org-prefix /api/bounties/{id}/escrow/* routes)
- participant-client: public list/detail, v2 application records
  (apply/edit/withdraw/me), competition join/leave
- use-participant hooks: useBountiesList/useBounty/useMyBountyApplication,
  useApply/Edit/WithdrawApplication, useJoin/LeaveCompetition, and escrow-op
  hooks (useSubmitBounty/useWithdrawSubmission/useContributeToBounty/
  useApplyToBountyEscrow/useWithdrawApplicationEscrow) driven through the
  runner, default MANAGED
- use-escrow: EscrowOpScope is now organizer | participant; the runner routes
  op-poll/submit-signed to the participant URLs
- keys/types/index: participant query keys, type aliases, public exports

MyBountyApplication is hand-typed until boundless-nestjs #331 lands and codegen
runs; useMyBountyActivity is deferred until the participant dashboard (#332).

Closes #621

* feat(bounty): public bounty marketplace (discover/list) (#645)

* feat(bounty): participant data layer (escrow client + hooks)

Add the builder/participant data layer to features/bounties, mirroring the
hackathon participant scope and reusing the shared escrow runner. The visible
builder UI (marketplace, detail, apply/submit/withdraw, my-bounties) consumes
this.

- participant-escrow-client: on-chain apply/submit/withdraw-application/
  withdraw-submission/contribute + participant op poll + submit-signed
  (the no-org-prefix /api/bounties/{id}/escrow/* routes)
- participant-client: public list/detail, v2 application records
  (apply/edit/withdraw/me), competition join/leave
- use-participant hooks: useBountiesList/useBounty/useMyBountyApplication,
  useApply/Edit/WithdrawApplication, useJoin/LeaveCompetition, and escrow-op
  hooks (useSubmitBounty/useWithdrawSubmission/useContributeToBounty/
  useApplyToBountyEscrow/useWithdrawApplicationEscrow) driven through the
  runner, default MANAGED
- use-escrow: EscrowOpScope is now organizer | participant; the runner routes
  op-poll/submit-signed to the participant URLs
- keys/types/index: participant query keys, type aliases, public exports

MyBountyApplication is hand-typed until boundless-nestjs #331 lands and codegen
runs; useMyBountyActivity is deferred until the participant dashboard (#332).

Closes #621

* feat(bounty): public bounty marketplace (discover/list)

Replace the /coming-soon placeholder at /bounties with a real public
marketplace, mirroring the hackathon browse and wired to the participant
data layer (#621).

- route app/(landing)/bounties/page.tsx + bounties metadata entry
- BountiesPage: search + status + mode filters, infinite scroll,
  loading/empty/error states
- BountyCard: mode badge (plain label), status, reward, organization,
  application-window date; links to /bounties/[id]
- BountiesFiltersHeader + colocated useInfiniteBounties (infinite query
  over listBounties)

Status + search filter server-side; mode narrows client-side (the public
list endpoint doesn't filter on mode). Category filter and a card submission
deadline are omitted because BountyPublicDto exposes neither — small backend
follow-ups.

Closes #622

* feat(bounty): bounty detail page (/bounties/[id]) (#646)

* feat(bounty): participant data layer (escrow client + hooks)

Add the builder/participant data layer to features/bounties, mirroring the
hackathon participant scope and reusing the shared escrow runner. The visible
builder UI (marketplace, detail, apply/submit/withdraw, my-bounties) consumes
this.

- participant-escrow-client: on-chain apply/submit/withdraw-application/
  withdraw-submission/contribute + participant op poll + submit-signed
  (the no-org-prefix /api/bounties/{id}/escrow/* routes)
- participant-client: public list/detail, v2 application records
  (apply/edit/withdraw/me), competition join/leave
- use-participant hooks: useBountiesList/useBounty/useMyBountyApplication,
  useApply/Edit/WithdrawApplication, useJoin/LeaveCompetition, and escrow-op
  hooks (useSubmitBounty/useWithdrawSubmission/useContributeToBounty/
  useApplyToBountyEscrow/useWithdrawApplicationEscrow) driven through the
  runner, default MANAGED
- use-escrow: EscrowOpScope is now organizer | participant; the runner routes
  op-poll/submit-signed to the participant URLs
- keys/types/index: participant query keys, type aliases, public exports

MyBountyApplication is hand-typed until boundless-nestjs #331 lands and codegen
runs; useMyBountyActivity is deferred until the participant dashboard (#332).

Closes #621

* feat(bounty): public bounty marketplace (discover/list)

Replace the /coming-soon placeholder at /bounties with a real public
marketplace, mirroring the hackathon browse and wired to the participant
data layer (#621).

- route app/(landing)/bounties/page.tsx + bounties metadata entry
- BountiesPage: search + status + mode filters, infinite scroll,
  loading/empty/error states
- BountyCard: mode badge (plain label), status, reward, organization,
  application-window date; links to /bounties/[id]
- BountiesFiltersHeader + colocated useInfiniteBounties (infinite query
  over listBounties)

Status + search filter server-side; mode narrows client-side (the public
list endpoint doesn't filter on mode). Category filter and a card submission
deadline are omitted because BountyPublicDto exposes neither — small backend
follow-ups.

Closes #622

* feat(bounty): bounty detail page (/bounties/[id])

The builder hub: shows the bounty, the caller's status, and a mode-aware
entry CTA. Wired to the participant data layer (#621).

- route app/(landing)/bounties/[id]/page.tsx
- BountyDetail: markdown description, prize tiers, mode/status badges,
  organization, reward pool + eligibility sidebar (reputation minimum /
  application window / max applicants / shortlist); loading + not-found
- BountyEntryCta: mode-aware CTA — Claim (open+single), Join (open+
  competition), Apply (application). Gated/explained when not accepting,
  the application window closed, or already applied; shows the caller's
  application status via useMyBountyApplication

The actual entry execution (forms / on-chain op) ships in #624; the CTA is
gated + labeled and hands off to it. applicationCreditCost is not in
BountyPublicDto so it's omitted from the eligibility panel.

Closes #623

* feat(bounty): apply / join / claim flow + edit/withdraw (mode-aware) (#647)

Fill the entry execution the detail-page CTA hands off to (#623), wired to
the participant data layer (#621). Covers all six modes.

- applicationSchema: mode-aware zod validation + body builders (light:
  proposalShort 100-300 words + estimatedDays + <=3 links; full: proposalFull
  500-2000 words + qualifications >=50 chars + <=6 links + optional video)
- BountyApplicationForm: conditional fields per entry type with live word
  count; reused for create + edit
- BountyEntryDialog: mode-aware modal — Apply (POST v2/applications) / Edit
  (PATCH); Join (POST v2/competition/join); Claim (on-chain apply escrow op,
  MANAGED, with progress + reputation pre-check). Wallet-gated.
- BountyEntryCta: opens the dialog and, for an active application, exposes
  Edit + Withdraw (application), Leave (competition), or on-chain Withdraw
  (single claim) behind a two-step confirm

Closes #624

* feat(bounty): submit work (on-chain anchor) + withdraw submission (#649)

After entry (claim/join/selection) the builder submits their deliverable,
anchored on-chain via the participant escrow runner (#621). Mirrors the
hackathon submission anchor.

- BountySubmitPanel (detail sidebar, shown when eligible: claimed/joined/
  SELECTED/SHORTLISTED): contentUri deliverable input -> submit escrow op
  (useSubmitBounty, MANAGED) with anchor progress (preparing -> anchoring ->
  confirmed) + tx-hash explorer link
- Withdraw submission via useWithdrawSubmission behind a two-step confirm
- Wallet-gated; guarded by entry eligibility

Persistent submission state across reloads is session-local until the #332
my-submission read lands in the schema; the submission-deadline gate is
enforced on-chain (not in BountyPublicDto).

Closes #625

* feat(bounty): builder "my bounties" activity + rewards receipt (#651)

The builder's /me surfaces for bounty applications, submissions, and reward
receipts, consuming the participant dashboard (#332) + earnings (#335).

- data layer: useMyBountyApplications / useMyBountySubmissions (the deferred
  useMyBountyActivity) via the legacy axios api (hand-typed rows, retry:false,
  degrading to empty until #332 lands in the schema)
- /me/bounties page: Applications + Submissions tabs with status/progress
  badges; won submissions show the reward amount + a payout tx-hash link;
  rows link to the detail page
- sidebar: "My Bounties" nav entry
- /me/earnings: the page already renders breakdown.bounties + activities
  generically (so #335 surfaces them); add a "View tx" link to reward
  activities (txHash cast until codegen)

Closes #626

* ci: auto-close linked issues on merge to any base branch (#652)

GitHub's built-in Closes/Fixes/Resolves auto-close only fires for PRs
merged into the default branch. Feature PRs here merge into integration
branches (feat/t-replace, etc.), leaving linked issues open. This adds a
pull_request_target workflow that parses the merged PR body and closes
the referenced same-repo issues on any base branch.

* feat(bounty): codegen refresh + retire hand-typed participant casts (#627) (#653)

The participant gap endpoints (applications/me, my-activity, results) have
landed in v2, so regenerate the OpenAPI schema and replace the two
hand-typed casts (MyBountyApplication, my-activity dashboard rows) with
their generated DTO aliases. Refresh openapi.snapshot.json so offline/CI
codegen matches. Nav entries (marketplace + /me sidebar) already shipped.

* feat: add template selection to hackathon generation dialog with new hook and UI component

* feat(bounty): submission page, marketplace redesign, and organizer requirements (#662)

* feat(bounty): submission metadata types, category filter, and wizard requirement toggles

Refresh the generated OpenAPI schema for the new public-bounty fields
(claimedBy, category, submissionDeadline, submissionRequirements) and the
submit-op metadata. Add the category query param to the marketplace list
client, the per-bounty my-submission read + hook, and the organizer
requirement toggles in the Configure wizard's submission step. Flatten the
category reputation baseline to 0 for testing and let the wizard accept a
0 floor.

* feat(bounty): marketplace card redesign, category tabs, and detail display

Bounty cards now show the organizer logo, category, a live due-date
countdown, and the USDC token logo (title only, no markdown bleed). Add a
category tab bar to the marketplace and mirror the same details on the
detail page, plus a mode-explainer tooltip. Single-claim bounties render a
'Claimed by' card linking to the claimant profile, and the application
withdraw button is gated while a submission is anchored.

* feat(bounty): dedicated submit page with metadata and media upload

Replace the single-input submit panel with a /bounties/[id]/submit page:
primary submission link plus optional documentation, tweet, and demo video
links and a drag-and-drop media uploader. Required fields follow the
bounty's organizer-configured requirements; on success it returns to the
detail page. The sidebar panel now routes here (new tab) and reflects the
submitted/withdraw state.

* feat: implement AI-assisted draft generation for hackathons and bounties

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Nnaji Benjamin <60315147+Benjtalkshow@users.noreply.github.com>
Co-authored-by: Benjtalkshow <chinedubenj@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant